package com.bocek.chakmapoint.model;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.awt.Graphics;
import java.awt.Point;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * A ZigZagLine slide item.
 * 
 * @author Emin Bugra Saral
 * @version 1.0
 */

public class CZigZagLine implements SlideItem {
	private boolean selected = false;
	private Color color;
	private int thickness;
	private ArrayList<Line2D> lines;
	private String name = "ZigZagLine";
	private Point startPoint;
	private boolean tempLine = false;

	public CZigZagLine() {
		setColor(Color.black);
		setThickness(1);
		lines = new ArrayList<Line2D>();
	}

	public CZigZagLine(Point p) {
		setColor(Color.black);
		setThickness(1);
		lines = new ArrayList<Line2D>();
		this.startPoint = p;
	}

	public void addPoint(Point p) {
		if (lines.isEmpty()) {
			this.addLine(startPoint, p);
		} else {
			Point2D lastPoint = getLines().get(getLines().size() - 1).getP2();
			this.addLine(lastPoint, (Point2D) p);
		}
	}

	public void drawDrag(Point p) {
		if (!tempLine) {
			addPoint(p);
			tempLine = true;
		} else {
			lines.remove(lines.size() - 1);
			addPoint(p);
		}
	}
	
	public void resetDrawDrag()
	{
		tempLine = false;
	}

	public String getName() {
		return this.name;
	}

	public boolean intersects(Rectangle r) {
		for (Line2D l : getLines()) {
			if (l.intersects(r))
				return true;
		}
		return false;
	}

	public void draw(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		Color previousColor = g2d.getColor();
		Stroke previousStroke = g2d.getStroke();

		g2d.setColor(color);
		g2d.setStroke(new BasicStroke(thickness));

		for (int i = 0; i < getLines().size(); i++) {
			g2d.draw(getLines().get(i));
		}

		if (isSelected()) {
			// dashed line
			g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND,
					BasicStroke.JOIN_ROUND, 0.0f, new float[] { 4.0f, 4.0f },
					0.9f));
			g2d.setColor(Color.BLUE);
			g2d.draw(this.drawSelection());
		}

		g2d.setStroke(previousStroke);
		g2d.setColor(previousColor);
	}

	public void move(Point delta) {
		for (int i = 0; i < getLines().size(); i++) {
			// update points
			Point2D p1 = new Point2D.Double(getLines().get(i).getP1().getX()
					+ delta.getX(), getLines().get(i).getP1().getY()
					+ delta.getY());
			Point2D p2 = new Point2D.Double(getLines().get(i).getP2().getX()
					+ delta.getX(), getLines().get(i).getP2().getY()
					+ delta.getY());
			// set new points of current line
			getLines().get(i).setLine(p1, p2);
		}
	}

	public void addLine(Point a, Point b) {
		getLines().add(new Line2D.Double(a, b));
	}

	public void addLine(Point2D a, Point2D b) {
		getLines().add(new Line2D.Double(a, b));
	}

	public ArrayList<Line2D> getLines() {
		return this.lines;
	}

	public Color getColor() {
		return color;
	}

	public void setColor(Color color) {
		this.color = color;
	}

	public int getThickness() {
		return thickness;
	}

	public void setThickness(int i) {
		this.thickness = i;
	}

	public boolean isPointInside(Point p) {
		for (Line2D l : getLines()) {
			if (l.ptLineDist(p) <= this.thickness + 3) {
				setSelected(true);
				return true;
			}
		}
		return false;
	}

	public boolean select(Point p) {
		if (isPointInside(p)) {
			this.setSelected(true);
			return true;
		} else {
			this.setSelected(false);
			return false;
		}
	}

	public void setSelected(boolean b) {
		this.selected = b;
	}

	public boolean deselect() {
		this.setSelected(false);
		return true;
	}

	public boolean isSelected() {
		return this.selected;
	}

	public boolean isOutsideFrame(Dimension frameDimension) {
		for (Line2D l : getLines()) {
			// check for x-coordinate
			if (l.getX1() > frameDimension.width || l.getX1() < 0
					|| l.getX2() > frameDimension.width || l.getX2() < 0) {
				return true;
			}
			// check for y-coordinate
			else if (l.getY1() > frameDimension.height || l.getY1() < 0
					|| l.getY2() > frameDimension.height || l.getY2() < 0) {
				return true;
			}
		}
		return false;
	}

	@Override
	public Rectangle drawSelection() {
		int minX = 999999;
		int minY = 9999999;
		int maxX = -999999;
		int maxY = -999999;

		for (Line2D l : getLines()) {
			if (l.getX1() <= minX)
				minX = (int) l.getX1();
			if (l.getX2() <= minX)
				minX = (int) l.getX2();
			if (l.getX1() >= maxX)
				maxX = (int) l.getX1();
			if (l.getX2() >= maxX)
				maxX = (int) l.getX2();

			if (l.getY1() <= minY)
				minY = (int) l.getY1();
			if (l.getY2() <= minY)
				minY = (int) l.getY2();
			if (l.getY1() >= maxY)
				maxY = (int) l.getY1();
			if (l.getY2() >= maxY)
				maxY = (int) l.getY2();
		}

		Point s = new Point(minX, minY);
		Point e = new Point(maxX, maxY);

		Rectangle r = new Rectangle((int) s.getX(), (int) s.getY(),
				(int) (e.getX() - s.getX()), (int) (e.getY() - s.getY()));
		r.setBounds(r.x - 2, r.y - 2, r.width + 4, r.height + 4);
		return r;

	}

	@Override
	public void fill() {

	}

	@Override
	public Element saveToXML(Document doc, int depth) throws ParserConfigurationException {
		/*
		 * <rectangle thickness="" color="" width="4" height="5" isFilled="true"
		 * depth="3" topX="2" leftY="3"/>
		 */

		// DEFAULT

		Element e = doc.createElement("zigzagline");
		e.setAttribute("thickness", Integer.toString(this.thickness));
		e.setAttribute("color", Integer.toString(this.color.getRGB()));
		e.setAttribute("depth", Integer.toString(depth));

		Element lines = doc.createElement("lines");

		for (Line2D l : getLines()) {
			Element line = doc.createElement("line");
			line.setAttribute("startX", Integer.toString((int) l.getX1()));
			line.setAttribute("endX", Integer.toString((int) l.getX2()));
			line.setAttribute("startY", Integer.toString((int) l.getY1()));
			line.setAttribute("endY", Integer.toString((int) l.getY2()));
			lines.appendChild(line);
		}

		e.appendChild(lines);
		
		return e;
	}
}
